Conversation
|
Idempotency: In The comment in Suggested fix: probe the installed version first, then install only when it doesn't match. - name: Check installed uv version
ansible.builtin.command: /usr/local/bin/uv --version
register: _uv_installed
failed_when: false
changed_when: false
become: true
become_user: root
when: django_use_uv
- name: Install uv (Astral)
vars:
_uv_installer_url: >-
{{
'https://astral.sh/uv/install.sh'
if django_uv_version == 'latest'
else 'https://astral.sh/uv/' ~ django_uv_version ~ '/install.sh'
}}
ansible.builtin.shell: |
set -eo pipefail
curl -LsSf {{ _uv_installer_url }} | env UV_INSTALL_DIR=/usr/local/bin sh
args:
executable: /bin/bash
become: true
become_user: root
when:
- django_use_uv
- _uv_installed.rc != 0
or django_uv_version == 'latest'
or django_uv_version not in (_uv_installed.stdout | default(''))The One sharp edge worth noting: |
|
Idempotency: In - name: Bootstrap pip into the uv-managed venv
ansible.builtin.command:
cmd: >-
uv pip install
--python {{ django_venv_path }}/bin/python
pip
environment:
UV_LINK_MODE: copy
become: true
become_user: "{{ django_system_user }}"
changed_when: true
when:
- django_use_uv| boolEvery playbook run reports this task as changed even when pip is already present. Two effects:
Suggested fix: add a - name: Bootstrap pip into the uv-managed venv
ansible.builtin.command:
cmd: >-
uv pip install
--python {{ django_venv_path }}/bin/python
pip
creates: "{{ django_venv_path }}/bin/pip"
environment:
UV_LINK_MODE: copy
become: true
become_user: "{{ django_system_user }}"
when:
- django_use_uv| boolNote this is not the same footgun as the Low severity / polish — the same always-changed pattern exists for the poetry and pipenv tasks in this file, so the author was being consistent. Just flagging it as a chance to do it right for the new mode. |
Summary
Adds an opt-in
django_use_uvinstall mode alongside the existingdjango_use_regular_old_pip/django_use_pipenv/django_use_poetrymodes. The mode readspyproject.toml+uv.lockfrom the project checkout and runsuv sync --frozen --no-devinto the same venv path the rest of the role expects (django_venv_path), so uwsgi systemd units, the wsgi config, etc. don't change.Off by default — no behavior change for existing consumers.
Why
Driven by onaio/tally-ho#561, which migrated tally-ho off
requirements/*.pipto apyproject.toml+uv.lockworkflow. Without this mode, the next deploy via onaio/ansible-tally-ho would fail at thepip install -r requirements/dev.pipstep (the file no longer exists upstream). The downstream wiring lives in onaio/ansible-tally-ho#25.What changed
defaults/main.yml— newdjango_use_uv,django_uv_version,django_uv_project_dir,django_uv_sync_args.tasks/python.yml— installs theuvbinary to/usr/local/bin/uvvia the official astral.sh installer when the mode is enabled. Idempotent viacreates:.tasks/install.yml— runsuv syncwithUV_PROJECT_ENVIRONMENT={{ django_venv_path }},UV_LINK_MODE=copy,UV_COMPILE_BYTECODE=1. Placed before the existingdjango_pip_packagestask so extras (uwsgi, celery, …) install into the uv-created venv unchanged.README.md— documents the new mode and tunables.molecule/uv/— new molecule scenario with a tiny self-contained fixture project (tests/fixtures/sample-uv-project/) seeded as a local git repo byprepare.yml. testinfra checks: uv binary present, venv populated,django-adminexists, and adjango_pip_packagesextra (click) lands in the same venv — verifying the cohabitation that tally-ho relies on for uwsgi.Test plan
ansible-lintclean (verified locally)yamllintclean (verified locally)molecule test --allexercises the newuvscenario on ubuntu2204